// GraphicsScene.cpp
//
#include "GLGraphicsScene.h"
#include "GLGraphicsView.h"

#include "UserInteractionManager.h"
#include "MouseStatus.h"


#include "OpenGL/OpenGL.h"
#include "OpenGL/Renderer.h"

#include <QPainter>
#include <QKeyEvent>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSceneWheelEvent>
#include <QGraphicsSceneContextMenuEvent>

#include "Utils/MemCheck.h"

using namespace QtFwk;

// -----------------------------------------------------------------------------------------------
GLGraphicsScene::GLGraphicsScene( QWidget *parent )
: QGraphicsScene(parent)
, view(parent)
{
	makeCurrent();

	OpenGL::glInitExtensions();

	renderer  = new OpenGL::Renderer;
	uim	      = new UserInteractionManager;
	zoomMode  = Settings::ZoomOnMouse;

	setSceneRect( parent->rect() );

	connect( this,SIGNAL(sceneRectChanged(const QRectF&)),SLOT(onResize(const QRectF&)) );
}

// -----------------------------------------------------------------------------------------------
GLGraphicsScene::~GLGraphicsScene()
{
	delete renderer;
	delete uim;
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::setZoomMode( Settings::ZoomMode zm )
{
	zoomMode = zm;
}

// -----------------------------------------------------------------------------------------------
//void GLGraphicsScene::translateScene()
//{
//	makeCurrent();
//	
//	MouseStatus ms = uim->mouseStatus();
//
//	Math::dvec2 curr ( renderer->convertWindowTo2D( ms.currPos().x(), ms.currPos().y() ) );
//	Math::dvec2 prev ( renderer->convertWindowTo2D( ms.prevPos().x(), ms.prevPos().y() ) );
//
//	if( false )
//		std::cout<<"Mouse at " << curr.x << " "<< curr.y << std::endl;
//
//	const Math::dvec3 diff = Math::dvec3(curr-prev,0.0);
//	renderer->camera().lookAt( renderer->camera().center()-diff );
//
//	//Math::dvec3 newcenter = renderer->center() - Math::dvec3( diff.x,diff.y, 0.0 );
//
//	//renderer->setCenter( newcenter );
//	
//	updateDrawables();
//	invalidate();
//}

// -----------------------------------------------------------------------------------------------
//void GLGraphicsScene::zoomScene()
//{
//	makeCurrent();
//
//	const MouseStatus mouseStatus = uim->mouseStatus();
//	const double z                = mouseStatus.wheel() ;
//
//
//	// get the center of the scene
//	Math::dvec3 target( renderer->camera().center() );
//	Math::dvec3 center( renderer->camera().center() );
//	
//	if( zoomMode == Settings::ZoomOnMouse )
//	{
//		// override center with mouse position
//		Math::dvec2 curr = renderer->convertWindowTo2D( mouseStatus.currPos().x(), mouseStatus.currPos().y() ) ;
//
//		target = Math::dvec3(curr,target.z);
//		renderer->camera().lookAt( (center - target)/Math::dvec3(z) + target ); //compute the new center position
//	}
//	
//	renderer->zoomInOut( z/*, target*/ );
//	updateDrawables();
//	invalidate();
//}
// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::updateDrawables()
{}


// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::onResize( const QRectF & rect )
{
	makeCurrent();

	renderer->setViewport( 0,0,rect.width(), rect.height() );	

	resizeScene( rect.width(), rect.height() );
	updateDrawables();
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::resizeScene( int w, int h)
{}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::trackMousePosition( const QPointF &mousePosition )
{
	currentPixelPoint = Math::dvec2( mousePosition.x(),height()-mousePosition.y()-1 );
	currentWorldPoint = renderer->convertWindowTo3D( mousePosition.x(), mousePosition.y(),true ) ;
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::onMouseMoved(){}
// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::onMousePressed(){}
// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::onMouseReleased(){}
// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::onMouseDoubleClick(){}
// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::onMouseWheel(){}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::focusInEvent( QFocusEvent *e)
{
	QGraphicsScene::focusInEvent(e);
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::focusOutEvent( QFocusEvent *e)
{
	QGraphicsScene::focusOutEvent(e);
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::mousePressEvent       ( QGraphicsSceneMouseEvent *e )
{
	// Propagate event to graphics items
	QGraphicsScene::mousePressEvent( e );

	if( e->isAccepted() )
		return;

	trackMousePosition( e->scenePos() );
	
	uim->updateMouse(e,true);
//	updating = true;
	
	onMousePressed();
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::mouseMoveEvent        ( QGraphicsSceneMouseEvent *e )
{
	// Propagate event to graphics items
	QGraphicsScene::mouseMoveEvent( e );

	if( e->isAccepted() )
		return;

	trackMousePosition( e->scenePos() );

	uim->updateMouse(e,false);

	onMouseMoved();
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::mouseReleaseEvent     ( QGraphicsSceneMouseEvent *e )
{
	// Propagate event to graphics items
	QGraphicsScene::mouseReleaseEvent( e );

	if( e->isAccepted() )
		return;

	trackMousePosition( e->scenePos() );

	uim->updateMouse(e,true);
//	updating = false;

	onMouseReleased();
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::wheelEvent            ( QGraphicsSceneWheelEvent *e )
{
	QGraphicsScene::wheelEvent( e );
	if( e->isAccepted() )
		return;

	trackMousePosition( e->scenePos() );

	uim->updateMouse(e,true);

	onMouseWheel();
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::mouseDoubleClickEvent ( QGraphicsSceneMouseEvent *e )
{
	QGraphicsScene::mouseDoubleClickEvent( e );

	if( e->isAccepted() )
		return;

	trackMousePosition( e->scenePos() );

	uim->updateMouse(e,true);

	onMouseDoubleClick();
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::contextMenuEvent      ( QGraphicsSceneContextMenuEvent *e )
{}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::keyPressEvent ( QKeyEvent *e )
{
	QGraphicsScene::keyPressEvent(e);
	if( e->isAccepted() )
		return;

	uim->updateKeyboard(e,true);
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::keyReleaseEvent ( QKeyEvent *e )
{
	QGraphicsScene::keyReleaseEvent(e);
	if( e->isAccepted() )
		return;

	uim->updateKeyboard(e,false);
}

// -----------------------------------------------------------------------------------------------
void GLGraphicsScene::makeCurrent()
{
	static_cast<GLGraphicsView*>(view)->makeCurrent();
}